package com.xnet.datahandler.common;

/**
 * 多级编号生成器 如001-002-003，级别从左至右依次递增，001为1级，002为2级，003为3级
 * 
 * @author 目田 2016年12月28日
 */
public class MultilevelNoGenerator {
	//计数器
	private static NoGenerator no;
	
	private MultilevelNoGenerator(Integer levels, Integer[] digit, String splitSymbol, String fillSymbol,
			Integer[] counter) {
		no = new NoGenerator(levels, digit, splitSymbol, fillSymbol, counter);
	}
	
	/**
	 * 配置计数器
	 * @param levels 编号级数
	 * @param digit 每级编号的位数，如三位数或四位数
	 * @param splitSymbol 每级编号之间的分隔符号
	 * @param fillSymbol 每级编号的位数不足时的补充字符,一般是0，如位数为3，则生成编号为001
	 * @param counter 计数器数组，存每级编号当前计数
	 * @return
	 * @author 徐目田
	 * 2016年12月29日
	 */
	public static MultilevelNoGenerator config(Integer levels, Integer[] digit, String splitSymbol, 
			String fillSymbol, Integer[] counter) {
		return new MultilevelNoGenerator(levels, digit, splitSymbol, fillSymbol, counter);
	}
	
	/**
	 * 获取编号
	 * @return 编号字符串
	 * @throws Exception
	 * @author 徐目田
	 * 2016年12月29日
	 */
	public String getNumber() throws Exception {
		return no.generate();
	}
	
	/**
	 * 重置编号计数器
	 * 
	 * @author 徐目田
	 * 2016年12月29日
	 */
	public void reset() {
		no.resetCounter();
	}

	public static void main(String[] args) throws Exception {
		//1、配置编号生成器
		MultilevelNoGenerator generator = MultilevelNoGenerator.config(1, new Integer[] { 3 }, "", "0",
				new Integer[] { 1 });
		int sum = 0;
		for (int jj = 0; jj < 100; jj++) {

			long start = System.currentTimeMillis();

			for (int n = 0; n < 100; n++) {

				System.out.println(generator.getNumber());//2、打印生成的编号
			}
			sum += (System.currentTimeMillis() - start);
			System.out.println(">>>>>>>>>>>>>>>>>>>>>time=" + (System.currentTimeMillis() - start));
		}
		System.out.println(sum);
	}
	
	static class NoGenerator {
		// 级别，多级编号，最左至右级别依次递增，如2级为001-002,
		private Integer levels;
		// 每个级别的位数
		private Integer[] digit;
		// 多级之间的分隔符，如为"-"，则编号生成为001-001
		private String splitSymbol;
		// 补位符号，如符号为0，则序号为1时，生成001
		private String fillSymbol;
		// 存储所有级别的计数器
		private Integer[] counter;

		public NoGenerator(Integer levels, Integer[] digit, String splitSymbol, String fillSymbol, 
				Integer[] counter) {
			super();
			this.levels = levels;
			this.digit = digit;
			this.splitSymbol = splitSymbol;
			this.fillSymbol = fillSymbol;
			this.counter = counter;
		}

		/**
		 * 生成编号
		 * 
		 * @return
		 * @throws Exception
		 * @author 徐目田 2016年12月28日
		 */
		public String generate() throws Exception {
			// 检查
			check();
			StringBuilder s = new StringBuilder();
			StringBuilder exp = new StringBuilder();
			// 逐级补零并连接各级编号
			for (int i = 0; i < counter.length; i++) {
				exp.append("%").append(fillSymbol).append(digit[i]).append("d");
				s.append(String.format(exp.toString(), counter[i]));
				if (i < counter.length - 1) {
					s.append(splitSymbol);
				}
				exp.delete(0, exp.length());
			}
			// 计数器累加
			counter(levels - 1);

			return s.toString();
		}

		/**
		 * 检查生成编号的参数是否符合规则
		 * 
		 * @return
		 * @throws Exception
		 * @author 徐目田 2016年12月28日
		 */
		public boolean check() throws Exception {
			if (digit.length != counter.length) {
				throw new Exception("The length of the array and the counter array does not match.");
			} else if (levels < 0) {
				throw new Exception("The level should be an integer greater than 1.");
			}
			return true;
		}

		/**
		 * 计数递增
		 * 
		 * @return 返回计数后的编号数组
		 */
		private Integer[] counter(Integer level) throws Exception {
			//System.out.println(Arrays.toString(counter));
			if(level < 0) {
				throw new Exception("Digital out of digit.");
			}
			Integer value = counter[level] + 1;
			if (level < 0) {
				return counter;
			}
			if (value > getMax(level)) {
				// 本级计数重置
				resetCounter(level);
				level--;
				counter(level);
			} else {
				counter[level]++;
			}
			return counter;
		}

		/**
		 * 获得指定级别的最大数值
		 * 
		 * @param level
		 *            编号级别
		 * @return
		 */
		private Integer getMax(Integer level) {
			Integer max = 0;
			for (int i = 0; i < digit[level]; i++) {
				max = max * 10 + 9;
			}
			return max;
		}

		/**
		 * 所有级别的计数器归一
		 */
		private void resetCounter() {
			for (int i = 0; i < counter.length; i++) {
				resetCounter(i);
			}
		}

		/**
		 * 指定级别的计数器归一
		 * 
		 * @param level
		 *            编号级别
		 */
		private void resetCounter(Integer level) {
			if (level == null)
				throw new NullPointerException();
			counter[level] = 1;
		}
	}

}
